#include "C_Map.h"
#include "C_SpaceObjectFactory.h"
#include "C_SpaceStar.h"



C_Map::C_Map()
: m_evMousePress(S_MousePressMove::makep())
, m_ready(true)
{
	m_proc = nullptr;
	m_procGen = nullptr;

	m_factoryObj = new C_SpaceObjectFactory(this);
	m_position.iX = 0;
	m_position.iY = 0;
	m_position.rX = 0.0f;
	m_position.rY = 0.0f;

	m_cellSize = 65.0f;

	m_debugDraw = false;
	this->doCount();

	//std::string path = "data/structs/space_elem.json";
	//std::ifstream file(path);
	//std::string line;
	//std::string strFile;
	//while (std::getline(file, line))
	//{
	//	strFile += line;
	//}
	C_SpaceStar star(this);
	star.generate();
	m_sql_spaceObj = new C_SQLiteSpaceObject("data/base/space_objects.db");
	m_sql_spaceObj->bind(this);
	m_sql_spaceObj->setFactory(m_factoryObj);

	//m_sql_spaceObj->add(SO_STAR, 0, 0, 0, 0, strFile);

	//if (m_sql_spaceObj->getReady())
	//{
	//	if (m_procGen != nullptr) m_procGen->join();
	//	delete m_procGen;
	//	m_procGen = new std::thread(
	//		std::bind(&C_SQLiteSpaceObject::loadSpaceObjects, m_sql_spaceObj,
	//		RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt))
	//	);
	//}

	//////////////////////////////////////////////////////////////////////////////////////////////////
	//////////	LOAD MAP OBJECT
	m_sql_spaceObj->loadSpaceObjects(RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt));
	m_sql_spaceReg = new C_SQLiteSpaceRegion("data/base/space_regions.db");
	
	//this->checkMap();

	if (m_ready == true)
	{
		if (m_proc != nullptr) m_proc->join();
		delete m_proc;
		m_proc = new std::thread(std::bind(&C_Map::checkMap, this));
	}
}


C_Map::~C_Map()
{
}

////////////////////////////////////////////////////////////////////////////////////////
//	DO COUNT
////////////////////////////////////////////////////////////////////////////////////////
void C_Map::doCount()
{
	m_wScrAmt = ceil((float)WINDOW_WIDTH / m_cellSize);
	m_hScrAmt = ceil((float)WINDOW_HEIGHT / m_cellSize);
	//testing
	m_wScrAmt = (m_wScrAmt < 4) ? 4 : m_wScrAmt;
	m_hScrAmt = (m_hScrAmt < 4) ? 4 : m_hScrAmt;

	m_wScr = WINDOW_WIDTH;
	m_hScr = WINDOW_HEIGHT;

	////////////////////////////////////////////////////////////
	////////////	SET AMT POINT FOR TEXTURE
	m_wTexAmt = m_position.iX + m_wScrAmt;
	m_hTexAmt = m_position.iY + m_hScrAmt;

	m_xTexAmt = m_position.iX - m_wScrAmt;
	m_yTexAmt = m_position.iY - m_hScrAmt;

	////////////////////////////////////////////////////////////
	////////////	SET FLOAT POINT FOR TEXTURE
	m_wTex = (m_wTexAmt - m_xTexAmt)*m_cellSize;
	m_hTex = (m_hTexAmt - m_yTexAmt)*m_cellSize;

	m_xTex = 0 - (m_wTex / 2 - m_wScr / 2) - m_position.rX - m_cellSize;
	m_yTex = 0 - (m_hTex / 2 - m_hScr / 2) - m_position.rY - m_cellSize;
}


////////////////////////////////////////////////////////////////////////////////////////
//	MOVE
////////////////////////////////////////////////////////////////////////////////////////
void C_Map::move(float x, float y)
{
	///////////////////////////////////////////////
	////////	IF COUNT MORE ONE
	if (x > m_cellSize)
	{
		int count = floor(x / m_cellSize);
		m_position.iX += count;
		x = x - (count * m_cellSize);
	}

	if (y > m_cellSize)
	{
		int count = floor(y / m_cellSize);
		m_position.iY += count;
		y = y - (count * m_cellSize);
	}
	///////////////////////////////////////////////
	////////	IF COUNT LESS ONE
	if (x < -m_cellSize)
	{
		int count = ceil(x / m_cellSize);
		m_position.iX += count;
		x = x - (count * m_cellSize);
	}

	if (y < -m_cellSize)
	{
		int count = ceil(y / m_cellSize);
		m_position.iY += count;
		y = y - (count * m_cellSize);
	}

	////////////////////////////////////////////////////////////////////
	/////////// SET POS
	m_position.rX += x;
	m_position.rY += y;

	////////////////////////////////////////////////////////////////////
	/////////// TESTING OVER
	if (m_position.rX > m_cellSize)
	{
		m_position.rX = m_position.rX - m_cellSize;
		m_position.iX++;
	}
	if (m_position.rY > m_cellSize)
	{
		m_position.rY = m_position.rY - m_cellSize;
		m_position.iY++;
	}

	////////////////////////////////////////////////////////////////////
	/////////// TESTING LESS
	if (m_position.rX < 0.0f)
	{
		m_position.rX = m_cellSize + m_position.rX;
		m_position.iX--;
	}
	if (m_position.rY < 0.0f)
	{
		m_position.rY = m_cellSize + m_position.rY;
		m_position.iY--;
	}

	this->doCount();
	//this->checkMap();
	/////////////////////////////////////////////////////////////////////////////////////
	////////	CHEKMAP
	if (m_ready == true)
	{
		if (m_proc != nullptr) m_proc->join();
		delete m_proc;
		m_proc = new std::thread(std::bind(&C_Map::checkMap, this));
	}

	//if (m_sql_spaceObj->getReady())
	//{
	//	if (m_procGen != nullptr) m_procGen->join();
	//	delete m_procGen;
	//	m_procGen = new std::thread(
	//		std::bind(&C_SQLiteSpaceObject::loadSpaceObjects, m_sql_spaceObj,
	//		RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt))
	//		);
	//}
	//m_sql_spaceObj->loadSpaceObjects(RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt));
}

void C_Map::checkMap()
{
	m_ready = false;

	bool leftTop = false;
	bool leftBottom = false;
	bool rightTop = false;
	bool rightBottom = false;

	S_Pointi lt = S_Pointi::create(ROUNDH(m_xTexAmt), ROUNDH(m_hTexAmt));
	S_Pointi rt = S_Pointi::create(ROUNDH(m_wTexAmt), ROUNDH(m_hTexAmt));
	S_Pointi lb = S_Pointi::create(ROUNDH(m_xTexAmt), ROUNDH(m_yTexAmt));
	S_Pointi rb = S_Pointi::create(ROUNDH(m_wTexAmt), ROUNDH(m_yTexAmt));

	bool mono = lt == rt && lt == lb && lt == rb;


	//LEFT TOP
	if (m_sql_spaceReg->find(lt.x, lt.y))
	{
		leftTop = true;
	}

	//RIGHT TOP
	if (m_sql_spaceReg->find(rt.x, rt.y))
	{
		rightTop = true;
	}

	//LEFT BOTTOM
	if (m_sql_spaceReg->find(lb.x, lb.y))
	{
		leftBottom = true;
	}

	//RIGHT BOTTOM
	if (m_sql_spaceReg->find(rb.x, rb.y))
	{
		rightBottom = true;
	}

	if (!leftTop)
	{
		this->generateMap(lt.x, lt.y);
		if (mono) return;
	}
	if (!rightTop)
	{
		this->generateMap(rt.x, rt.y);
	}
	if (!leftBottom)
	{
		this->generateMap(lb.x, lb.y);
	}
	if (!rightBottom)
	{
		this->generateMap(rb.x, rb.y);
	}

	m_ready = true;
}

void C_Map::generateMap(int x, int y)
{
	//set randome type
	typedef boost::mt19937 RGNtype;
	RGNtype rng(std::time(0));

	////////////////////////////////////////////////////////////
	////////	STAR POSITION INSIDE RECT
	boost::uniform_int <> rand_starAE(0, 100);
	boost::variate_generator<RGNtype, boost::uniform_int<> > doStarAE(rng, rand_starAE);

	boost::uniform_int <> rand_starIR(0, 150);
	boost::variate_generator<RGNtype, boost::uniform_int<> > doStarIR(rng, rand_starIR);

	for (int i = 0; i < 800; i++)
	{
		C_SpaceStar *star = new C_SpaceStar(this);
		star->generate();
		int aeX = x + doStarAE();
		int aeY = y + doStarAE();
		int irX = doStarIR();
		int irY = doStarIR();
		m_sql_spaceObj->add(SO_STAR, aeX, aeY, doStarIR(), doStarIR(), star->getJSON());
	}

	m_sql_spaceReg->add(x, y);
	//if (m_sql_spaceObj->getReady())
	//{
	//	if (m_procGen != nullptr) m_procGen->join();
	//	delete m_procGen;
	//	m_procGen = new std::thread(
	//		std::bind(&C_SQLiteSpaceObject::loadSpaceObjects, m_sql_spaceObj,
	//		RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt))
	//		);
	//}

	///////////////////////////////////////////////////////////////////////////////////////////////
	/////////	LOAD MAP OBJECTs
	m_sql_spaceObj->loadSpaceObjects(RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt));
}

void C_Map::handleEvent(sf::Event e)
{
	switch (e.type)
	{
	case sf::Event::MouseWheelMoved:
	{
									   this->zoom(e.mouseWheel.delta * 10);
									   WR("CELL SIZE: " << m_cellSize);
									   break;
	}
	case sf::Event::KeyPressed:
	{
								  if (e.key.code == sf::Keyboard::W)
								  {
									  this->move(0.0f, -10.0f);
								  }
								  if (e.key.code == sf::Keyboard::A)
								  {
									  this->move(-10.0f, 0.0f);
								  }
								  if (e.key.code == sf::Keyboard::D)
								  {
									  this->move(10.0f, 0.0f);
								  }
								  if (e.key.code == sf::Keyboard::S)
								  {
									  this->move(0.0f, 10.0f);
								  }
								  break;
	}
	case sf::Event::MouseButtonPressed:
	{
										  m_evMousePress->onPress(e.mouseButton.x, e.mouseButton.y);
										  break;
	}
	case sf::Event::MouseButtonReleased:
	{
										  m_evMousePress->onRelease();
										  m_factoryObj->remove(RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt));
										  m_sql_spaceObj->loadSpaceObjects(RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt));
										  break;
	}
	case sf::Event::MouseMoved:
	{
										   if (m_evMousePress->isPress)
										   {
											   m_evMousePress->move(e.mouseMove.x, e.mouseMove.y);
											   this->move(-m_evMousePress->x, -m_evMousePress->y);
										   }
										   break;
	}
	default: break;
	}

	////////////////////////////////////////////////////////////////////////
	////////	FACTORY HANDLE EVENTS
	m_factoryObj->handleEvent(e);
}

void C_Map::render()
{
	float vertex[] =
	{
		0.0f,		0.0f,
		m_cellSize, 0.0f,
		m_cellSize, m_cellSize,
		0.0f,		m_cellSize
	};
	sf::Text num;
	num.setFont(*FONT_1);
	num.setCharacterSize(14);

	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(2, GL_FLOAT, 0, vertex);
	glColor3f(0.0f, 1.0f, 0.0f);
	for (int x = 0; x < m_wTexAmt - m_xTexAmt; x++)
	{
		for (int y = 0; y < m_hTexAmt - m_yTexAmt; y++)
		{
			//num.setString(std::to_string(m_xTexAmt + x) + "," + std::to_string(m_yTexAmt + y));
			//num.setPosition(sf::Vector2f(m_xTex + x*m_cellSize, m_yTex + y*m_cellSize));
			//m_rWindow->draw(num);

			glPushMatrix();
				glTranslatef(m_xTex + x*m_cellSize, m_yTex + y*m_cellSize, 0.0f);
				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
					glDrawArrays(GL_QUADS, 0, 4);
				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
			glPopMatrix();
		}
	}
	glDisableClientState(GL_VERTEX_ARRAY);

	////////////////////////////////////////////////////////////////////////
	////////	FACTORY RENDER
	m_factoryObj->render();
}

void C_Map::update()
{
	////////////////////////////////////////////////////////////////////////
	////////	FACTORY UPDATE
	m_factoryObj->update();
}

sf::Vector2f C_Map::getPixCoord(int x, int y)
{
	if (x < m_xTexAmt || x > m_wTexAmt || y < m_yTexAmt || y > m_hTexAmt)
	{
		return sf::Vector2f(0.0f, 0.0f);
	}

	float rX = m_xTex + (x - m_xTexAmt)*m_cellSize;
	float rY = m_yTex + (y - m_yTexAmt)*m_cellSize;
	
	return sf::Vector2f(rX, rY);
}

void C_Map::zoom(float z)
{ 
	float last = m_cellSize;
	m_cellSize += z; 
	if (m_cellSize < 25.0f)
	{
		m_cellSize = 25.0f;
	}
	if (m_position.rX != 0) m_position.rX *= m_cellSize / last;
	if (m_position.rY != 0) m_position.rY *= m_cellSize / last;
	//m_position.rX += z;
	//m_position.rY += z;

	if (m_position.rX < 0.0f) m_position.rX = 0.0f;
	if (m_position.rY < 0.0f) m_position.rY = 0.0f;

	this->doCount();
	//this->checkMap();
	if (m_ready == true)
	{
		if(m_proc!= nullptr) m_proc->join();
		delete m_proc;
		m_proc = new std::thread(std::bind(&C_Map::checkMap, this));
	}

	//m_sql_spaceObj->loadSpaceObjects(RANGEi(m_xTexAmt, m_wTexAmt), RANGEi(m_yTexAmt, m_hTexAmt));
}


void C_Map::addObject(VC_Object* obj)
{
	m_factoryObj->add(obj);
}